#define	_J_PROCESI_C_
#include "procesi.h"

#include "razno.h"
#include "liste.h"

//OPISNICI procesa
j_proces_t *j_opisnik_procesa;

inline void j_postavi_opisnike_procesa ( void *opisnici_za_procese )
{
	j_opisnik_procesa = opisnici_za_procese;
}

//OPISNICI procesa (samo kazaljke na njih)
ZAUZMI ( j_proces_p, j_proces, NAJ_PROCESA );

//stvara novi proces s pocetnom dretvom - j-funckija
int j_stvori_proces ( void *param )
{
	struct {
		void ( *poc_funkc )( void * );	//pocetna funckija dreve
		void *param;			//parametar za funkciju
		void *stog;			//pocetni stog
		int prio;			//prioritet
		int rasp;			//koji rasporedjivac? FIFO, RR

		bool u_jezgri;			//nacin rada - privilegirani?
		bool stranicenje;		//da li staviti proces u sustav
						//stranicenja?
		void *pocetna_adresa;
		uint32 velicina;

	} *p = param;

	PARAMNULL ( p );

	int id = DOHVATI ( j_proces );

	if ( id == -1 )
	{
		j_ispisi ( "Nema slobodnog opisnika procesa\n" );
		return -1;
	}

	j_proces_t *proces = j_proces[id] = &j_opisnik_procesa[id];

	proces->id = id;
	proces->zast = 0;

	if ( p->u_jezgri )
		proces->zast |= PROCES_JEZGRE;

	if ( p->stranicenje )
		proces->zast |= STRANICENJE;

	j_inicijaliziraj_spremnik_za_proces (	id,
						p->pocetna_adresa,
						p->velicina,
						p->u_jezgri,
						p->stranicenje );

	int id_dretve = j_stvori_dretvu_i ( p, id );

	if ( id_dretve == -1 ) {
		OBRISI ( j_proces, id );

		return -1;
	}
	else {
		proces->dretva = j_dohvati_opisnik ( id_dretve );
		proces->dretva->iduci_p = NULL; //prva dretva procesa

		return id;
	}
}

//doraditi/ispitati
int j_zavrsi_proces ( void *param )
{
	int *pid = param;
	int id, id_dretve;

	if (pid == NULL)
		id = j_aktivni_proces();
	else
		id = *pid;

	if ( id < 0 || id > NAJ_PROCESA || PROVJERI_SLOBODNO ( j_proces, id ) ){
		j_ispisi ( "Nepoznati proces\n" );
		return -1;
	}

	j_proces_t *proces = j_proces[id];
	
	if ( proces->zast & GASI_SE )
		return 0; //vec je u postupku

	proces->zast |= GASI_SE;

	//obrisi dretve - popravi
	while ( proces->dretva != NULL ) {
		//zavrsi dretvu
		id_dretve = j_opdr_id ( proces->dretva );

		//makni je iz liste za proces
		proces->dretva = proces->dretva->iduci_p;
		proces->dretva->id_procesa = -1;

		j_zavrsi_dretvu ( &id_dretve );
	}

	j_oslobodi_spremnicki_prostor_procesa ( &proces->spremnik );

	OBRISI ( j_proces, id );

	return 0;
}

//poziva se pri stvaranju nove dretve
void j_proces_postavi_dretvu ( void *_opd, int id_procesa, void *stog,
			        void *pokreni_dretvu,
			        void *poc_funkc, void *param )
{
	j_proces_t *proces = j_proces[id_procesa];
	j_dretva_t *opd = _opd;
	int i = -1;
	void *l_stog, *a_stog;
	void *l_kontekst, *a_kontekst;

	//treba li postaviti kontekst za dretvu?
	if ( !( proces->zast & STRANICENJE ) )
	{
		opd->id_opisnika = -1;
		opd->kontekst = j_spremnik_za_kontekst ( opd->id );
		//apsolutna adresa!

		a_kontekst = opd->kontekst;
		l_kontekst = NULL; //nije potreban
		//nije ni dohvatljiv iz adresnog prostora procesa!
	}
	else {
		i = NADJI_PRVI ( proces->spremnik.mkontekst_dretvi, NAJ_DRETVI);
		if ( i == -1 )
			j_zaustavi_potpuno (
				"Nema mjesta za kontekst nove dretve\n" );
		
		opd->id_opisnika = i;

		l_kontekst = proces->spremnik.kontekst_dretvi + 
				i * sizeof (arh_kontekst_t);
		//relativna adresa!

		a_kontekst = j_puj ( id_procesa, l_kontekst );
		opd->kontekst = a_kontekst;
	}

	opd->iduci_p = proces->dretva;
	proces->dretva = opd;

	if ( stog == NULL )
	{
		i = NADJI_PRVI ( proces->spremnik.mstogovi, NAJ_DRETVI );

		if ( i == -1 )
			j_zaustavi_potpuno("Nema mjesta za stog nove dretve\n");

		l_stog = proces->spremnik.stogovi - i * VELICINA_STOGA;
		a_stog = j_puj ( id_procesa, l_stog );
		opd->id_stoga = i;
	}
	else //zadan je stog, mora biti u prihvatljivim adresama procesa
	{
		l_stog = stog;
		a_stog = j_puj ( id_procesa, l_stog );
		opd->id_stoga = -1;
	}

	arh_pripremi_novu_dretvu ( &proces->spremnik.segmentacija, 
				   a_kontekst, l_kontekst, a_stog, l_stog,
				   pokreni_dretvu, poc_funkc, param );
}

//gotovu dretvu makni iz popisa procesa
void j_makni_dretvu_procesu ( int id_procesa, void *_opd )
{
	j_proces_t *proces = j_proces[id_procesa];
	j_dretva_t *opd = _opd, *iter = proces->dretva;

	//oslobodi opisnik i stog
	if ( opd->id_opisnika != -1 )
		POSTAVI_SLOBODNO ( proces->spremnik.mkontekst_dretvi,
				   NAJ_DRETVI,
				   opd->id_opisnika );

	if ( opd->id_stoga != -1 )
		POSTAVI_SLOBODNO ( proces->spremnik.mstogovi, NAJ_DRETVI,
				   opd->id_stoga );

	if ( iter == opd ) {
		proces->dretva = iter->iduci_p;
	}
	else {
		while ( iter->iduci_p ) {
			if ( iter->iduci_p == opd ) {
				iter->iduci_p = opd->iduci_p;
				break;
			}
			iter = iter->iduci_p;
		}
	}

	if ( proces->dretva == NULL && !( proces->zast & GASI_SE ) &&
	     !PROVJERI_SLOBODNO ( j_proces, id_procesa ) )
		j_zavrsi_proces ( &id_procesa );
}

//dohvati opisnik spremnika za proces
void *j_oppr_spremnik ( int id )
{
	return &j_proces[id]->spremnik;
}

//dohvati opisnik spremnika za proces
void *j_oppr_arh_spremnik ( int id )
{
	return &j_proces[id]->spremnik.segmentacija;
}

//pretvara adresu jezgre u adresu za program
void *j_jup ( int id_procesa, void *adr_u_jezgri )
{
	if ( !j_proces[id_procesa]->spremnik.stranicenje )
	{
		return arh_jup ( &j_proces[id_procesa]->spremnik.segmentacija,
				 adr_u_jezgri );
	}
	else {
		j_ispisi ( "Ovo ne funkcionira!" );
		return NULL;
	}
}

//pretvara adresu programa u adresu koja je dohvatljiva iz jezgre
void *j_puj ( int id_procesa, void *adr_u_programu )
{
	void *adresa;
	int povvr = 0;
	int id;

	if ( id_procesa == -1 )
		id = j_aktivni_proces ();
	else
		id = id_procesa;

	if ( !j_proces[id]->spremnik.stranicenje )
	{
		adresa = arh_puj ( &j_proces[id]->spremnik.segmentacija,
				   adr_u_programu );
	}
	else {
		povvr = j_adresa_u_jezgri ( adr_u_programu, &adresa,
					    &j_proces[id]->spremnik );

		if ( povvr ) {
			j_ispisi ( "Greska u pretvaranju adrese %x)!\n", 
				   adr_u_programu );
			adresa = NULL;
		}
	}

	return adresa;
}

inline uint j_velicina_opisnika_procesa ()
{
	return sizeof (j_proces_t);
}


//test procesa u jezgrinom prostoru (u apsolutnim adresama)

//stog za takav proces
uint8 proces_x_stog[VELICINA_STOGA];
void *pproces_x_stog = POCETAK_STOGA(proces_x_stog, VELICINA_STOGA);

#include <pozivi_jezgre.h>
#include <ispis.h>
#include <vrijeme.h>
#include <programi.h>
void proces_x ( void *param )
{
	//moze koristiti samo funkcije jezgre:
	//	ili pozivati izravno ili preko prekida
	//"sucelje" je u relativnim adresama i ne moze se izravno koristiti,
	//ali ... (vidi primjere)

	//izravnim pozivom jezgrine funkcije:
	j_ispisi ( "[%s] Eto opakog procesa!\n", __FUNCTION__ );


	//pozivom jezgrine funkcije prekidom:
	struct test_ispisa { //parametri redom ...
		char *poruka;
		char *param1;
	} ti;
	ti.poruka = "[%s] Ispis preko poziva jezgrinih funkcija!\n";
	ti.param1 = (char *) __FUNCTION__;
	J_FUNKCIJA ( ISPISI, &ti );


	//"igranje s adresama"
	//oprez: u tim se funkcijama ne smiju koristiti globalne varijable
	extern char programi_pocetak;
	uint odmak = (uint) &programi_pocetak;

	(ispisi + odmak) ( "[%s] Preko 'sucelja'! :)\n", __FUNCTION__ );

	vrijeme_t koliko;
	koliko.sekunde = 1;
	koliko.nsekunde = 0;

	( odgodi + odmak ) (koliko);

	j_ispisi ( "[%s] Kraj opakog procesa!\n", __FUNCTION__ );


	//iduci poziv ne bi funkcionirao jer se pri ispisu koriste adrese
	//konstanti koje su u "relativnom obliku"

	// ( pocetna_dretva + odmak ) ( NULL );
}

